package com.xishu.service;

import com.google.common.collect.Lists;
import com.xishu.bo.TicketAndLimit;
import com.xishu.config.Config;
import com.xishu.entity.Company;
import com.xishu.entity.NameAndId;
import com.xishu.entity.customer.CustomerTicket;
import com.xishu.entity.customer.MarketTask;
import com.xishu.entity.customer.VipLevel;
import com.xishu.entity.customer.VipLevelTicketConfig;
import com.xishu.entity.order.Order;
import com.xishu.entity.shop.CompanyMainItem;
import com.xishu.entity.shop.DiscountTicket;
import com.xishu.entity.shop.Shop;
import com.xishu.entity.shop.ShopTicketMapping;
import com.xishu.exception.ResponseStatusException;
import com.xishu.response.VerifyUtil;
import com.xishu.service.order.base.OrderService;
import com.xishu.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.io.File;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.*;
import static com.xishu.response.ResponseStatus.*;

public class DiscountTicketService implements Tools {
    private static DiscountTicketService instance = new DiscountTicketService();
    private CommonService commonService = CommonService.getInstance();
    private static Logger logger = LoggerFactory.getLogger(DiscountTicketService.class);

    private Config config = Config.getInstance();


    private DiscountTicketService() {
    }

    public static DiscountTicketService getInstance() {
        return instance;
    }

    /**
     * 同步添加父优惠券的值
     *
     * @param discountTicket
     */
    public void syncParentTicket(DiscountTicket discountTicket) throws Exception {
        if (discountTicket == null) {
            return;
        }

        if (discountTicket.getParentId() == null) {
            return;
        }

        Optional<DiscountTicket> discountTicketOptional = commonService.searchOneOptional(discountTicket.getParentId(), DiscountTicket.class);
        //父优惠券已经不在了
        if (!discountTicketOptional.isPresent()) {
            logger.info("can not find the parent ticket {}", discountTicket.getId());
            return;
        }

        DiscountTicket parentDiscountTicket = discountTicketOptional.get();
        discountTicket.setShopList(parentDiscountTicket.getShopList());

        //生成的消费后金额券将采用消费后金额的里面的产生券时可以使用的场景
        if (!getBoolean(parentDiscountTicket.getOnlineTicket()) && getInt(parentDiscountTicket.getTicketType()) == DISCOUNT_TICKET_TYPE_AFTER_COST) {
            discountTicket.setSceneList(parentDiscountTicket.getAfterSceneList());
        } else {
            discountTicket.setSceneList(parentDiscountTicket.getSceneList());
        }

        //如果还是菜品券，那么同步修改主菜
        if (getBoolean(parentDiscountTicket.getItemTicket())) {
            discountTicket.setMainItemIdList(parentDiscountTicket.getMainItemIdList());
        }
    }

    /**
     * 搜索优惠卷
     *
     * @param ticketId
     * @return
     * @throws Exception
     */
    public DiscountTicket findTicket(Long ticketId) throws Exception {
        DiscountTicket discountTicket = commonService.findEntity(ticketId, DiscountTicket.class);
        syncParentTicket(discountTicket);
        return discountTicket;
    }

    /**
     * 查询优惠券
     *
     * @param ticketId
     * @return
     * @throws Exception
     */
    public Optional<DiscountTicket> findTicketOptional(Long ticketId) throws Exception {
        Optional<DiscountTicket> discountTicketOptional = commonService.searchOneOptional(ticketId, DiscountTicket.class);

        if (discountTicketOptional.isPresent()) {
            syncParentTicket(discountTicketOptional.get());
        }

        return discountTicketOptional;
    }

    /**
     * 搜索优惠券，并且是否要返回主菜的名称
     *
     * @param ticketId
     * @param showCompanyMainItem
     * @return
     */
    public DiscountTicket findTicket(Long ticketId, Boolean showCompanyMainItem) throws Exception {
        DiscountTicket ticket = findTicket(ticketId);
        ticket.setExpiredTime(ticket.getEndTime());

        if (getBoolean(showCompanyMainItem)) {
            addCompanyMainItemList(ticket);
        }

        return ticket;
    }

    /**
     * 通过父ID来查询所有的优惠卷
     *
     * @param parentId
     * @return
     */
    public List<DiscountTicket> findDiscountTicketByParentId(Long parentId) throws Exception {
        DiscountTicket discountTicket = new DiscountTicket();
        discountTicket.setParentId(parentId);
        List<DiscountTicket> discountTicketList = commonService.searchAll(discountTicket);
        for (DiscountTicket ticket : discountTicketList) {
            syncParentTicket(ticket);
        }

        return discountTicketList;
    }

    /**
     * 产生优惠卷码,一直找到不存在的优惠卷
     *
     * @return
     */
    public String generateCode(Long companyId) throws Exception {
        while (true) {
            String generateNumberCode = RandomUtil.generateNumberCode(10);
            DiscountTicket reqDiscountTicket = new DiscountTicket();
            reqDiscountTicket.setCode(generateNumberCode);
            reqDiscountTicket.setCompanyId(companyId);
            DiscountTicket discountTicket = commonService.searchOne(reqDiscountTicket);

            //上传条件码图片
            File createBarCode = ImgService.getInstance().createBarCode(generateNumberCode);
            File barCodeFile = MongoId.getInstance().generateTmpFileWithName(String.format("discount-%s.png", generateNumberCode));
            FileUtil.copyFile(createBarCode, barCodeFile);
            ObjectService.getInstance().uploadObject(barCodeFile);

            if (discountTicket == null) {
                return generateNumberCode;
            }
        }
    }

    /**
     * 通过优惠码来查询优惠卷
     *
     * @param code
     * @param companyId
     * @return
     */
    public DiscountTicket findTicketByCode(String code, Long companyId) {
        DiscountTicket ticket = new DiscountTicket();
        ticket.setCode(code);
        ticket.setCompanyId(companyId);
        DiscountTicket discountTicket = commonService.searchOne(ticket);

        try {
            syncParentTicket(discountTicket);
        } catch (Exception e) {
            logger.error("e", e);
        }

        return discountTicket;
    }

    /**
     * 创建商铺与优惠卷的映射
     *
     * @param discountTicket
     */
    public void createMapping(DiscountTicket discountTicket) {
        //如果是消费后优惠卷，采用映射的方式
        for (NameAndId nameAndId : discountTicket.getShopList()) {
            Long shopId = nameAndId.getId();
            ShopTicketMapping shopTicketMapping = new ShopTicketMapping();
            shopTicketMapping.setShopId(shopId);
            shopTicketMapping.setTicketId(discountTicket.getId());
            shopTicketMapping.setTicketType(discountTicket.getTicketType());
            try {
                commonService.createObject(shopTicketMapping);
            } catch (Exception e) {
                logger.error("e", e);
            }
        }
    }

    /**
     * 删除商铺与优惠卷的映射关系
     *
     * @param discountTicket
     * @throws Exception
     */
    public void deleteMapping(DiscountTicket discountTicket) throws Exception {
        ShopTicketMapping shopTicketMapping = new ShopTicketMapping();
        shopTicketMapping.setTicketId(discountTicket.getId());
        commonService.delete(shopTicketMapping, false, null);
    }

    /**
     * 查询消费后金额优惠卷
     *
     * @returnb
     */
    public List<DiscountTicket> searchAfterCostTicket(Long companyId, Long shopId) {
        DiscountTicket discountTicket = new DiscountTicket();
        discountTicket.setCompanyId(companyId);
        discountTicket.setTicketType(DISCOUNT_TICKET_TYPE_AFTER_COST);
        discountTicket.setSortField(new String[]{"createTime"});
        discountTicket.setSortType("DESC");
        List<DiscountTicket> discountTicketList = commonService.searchList(discountTicket);

        return discountTicketList.stream().filter(ticket -> {
            List<Long> shopIdList = getList(ticket.getShopList()).stream().map(s -> s.getId()).collect(Collectors.toList());
            return shopIdList.contains(shopId.longValue());
        }).collect(Collectors.toList());
    }

    /**
     * 过滤出符合当前时间的优惠卷
     * <p>
     * 按消费金额高的来判断先 依次往下
     *
     * @param discountTicketList
     * @return
     */
    public Optional<DiscountTicket> filterTicket(List<DiscountTicket> discountTicketList, Order order) {
        if (isEmpty(discountTicketList)) {
            return Optional.empty();
        }

        List<DiscountTicket> filterDiscountTicket = new ArrayList<>();

        for (DiscountTicket ticket : discountTicketList) {
            List<NameAndId> sceneList = ticket.getSceneList();

            if (isEmpty(sceneList)) {
                continue;
            }

            //金额都小了,要用户的真实付款金额匹配上了
            if (getDouble(order.getUserCost()) < getDouble(ticket.getAtLeastCost())) {
                continue;
            }

            //场景要匹配上
            boolean match = sceneList.stream().filter(p -> equals(p.getId(), order.getSceneId())).findAny().isPresent();

            if (!match) {
                continue;
            }

            //券的时间要对上
            if (ticket.getStartTime() != null && ticket.getEndTime() != null) {
                long currentTimeMillis = System.currentTimeMillis();
                //时间没有匹配上
                if (!(currentTimeMillis > ticket.getStartTime() && currentTimeMillis < ticket.getEndTime())) {
                    continue;
                }
            }

            //到这里意味着时间和金额都匹配上了
            filterDiscountTicket.add(ticket);
        }

        if (isEmpty(filterDiscountTicket)) {
            logger.info("do not have filter discount ticket");
            return Optional.empty();
        }

        //倒序排序
        filterDiscountTicket.sort((t1, t2) -> -(getDouble(t1.getAtLeastCost()).intValue() - getDouble(t2.getAtLeastCost()).intValue()));

        return Optional.of(filterDiscountTicket.get(0));
    }

    /**
     * 创建一个满减的优惠卷
     *
     * @return
     */
    public String generateSatisfyAndCutTicket(DiscountTicket discountTicket, Order order) throws Exception {
        logger.info("discountTicket id is {}", discountTicket.getId());
        Long shopId = order.getShopId();
        Shop shop = ShopService.getInstance().findShopById(shopId);
        //创建一个满减的优惠卷
        Double afterCash = discountTicket.getAfterCash();

        if (getDouble(afterCash) == 0d) {
            Double afterPercent = getDouble(discountTicket.getAfterPercent());

            if (afterPercent == 0) {
                logger.info("not config after percent");
                return "";
            }

            afterCash = formatMoneyDouble(order.getUserCost() * afterPercent / 100d);
        }

        DiscountTicket satisfyAndCutTicket = new DiscountTicket();
        String code = generateCode(shop.getCompanyId());
        satisfyAndCutTicket.setDiscountCash(afterCash);
        satisfyAndCutTicket.setCode(code);
        satisfyAndCutTicket.setCompanyId(shop.getCompanyId());
        satisfyAndCutTicket.setAtLeastCost(getDouble(discountTicket.getAfterAtLeast()));
        //设置卷的有效期
        satisfyAndCutTicket.setStartTime(System.currentTimeMillis());
        satisfyAndCutTicket.setEndTime(DateUtil.endTimeInDay(System.currentTimeMillis() + DateUtil.ONE_DAY * discountTicket.getAfterValidDay()));
        //从优惠的配置场景复制到满减的使用场景里面
        satisfyAndCutTicket.setSceneList(new ArrayList<>());
        satisfyAndCutTicket.getSceneList().addAll(discountTicket.getAfterSceneList());
        satisfyAndCutTicket.setTicketType(DISCOUNT_TICKET_TYPE_CASH);
        satisfyAndCutTicket.setShopList(discountTicket.getShopList());
        //添加优惠卷绑定的订单
        satisfyAndCutTicket.setShopId(order.getShopId());
        satisfyAndCutTicket.setCreateSubOrderId(order.getId());
        satisfyAndCutTicket.setParentId(discountTicket.getId());
        satisfyAndCutTicket.setTangshi(discountTicket.getTangshi());
        satisfyAndCutTicket.setTakeout(discountTicket.getTakeout());
        satisfyAndCutTicket.setMultiUsed(discountTicket.getMultiUsed());
        satisfyAndCutTicket.setName_en(discountTicket.getName_en());
        satisfyAndCutTicket.setName_zh(discountTicket.getName_zh());
        satisfyAndCutTicket.setName(discountTicket.getName());
        commonService.createObject(satisfyAndCutTicket);
        return satisfyAndCutTicket.getCode();
    }

    /**
     * 产生横向的优惠卷
     * <p>
     * 3张一组
     *
     * @param discountTicketList
     * @return
     */
    public File generateHorizontalTicketFile(List<DiscountTicket> discountTicketList, Company company, int index, boolean zh) throws Exception {
        //先判断能否被6整除，如果不能，则依次添加
        int leftCount = discountTicketList.size() % 3;
        if (leftCount != 0) {
            for (int i = 0; i < 3 - leftCount; i++) {
                discountTicketList.add(new DiscountTicket());
            }
        }

        StringBuilder sb = new StringBuilder();
        sb.append("<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "  <meta charset=\"UTF-8\">\n" +
                "  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
                "  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
                "  <style>\n" +
                "    *{margin: 0;padding: 0;box-sizing: border-box;font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Liberation Sans\", \"PingFang SC\", \"Microsoft YaHei\", \"Hiragino Sans GB\", \"Wenquanyi Micro Hei\", \"WenQuanYi Zen Hei\", \"ST Heiti\", SimHei, SimSun, \"WenQuanYi Zen Hei Sharp\", sans-serif;}\n" +
                "    html, body{width: 100%;height: 100%;font-size: 20px;}\n" +
                "    .paper{width: 42rem;height: 59.4rem;display: flex;flex-wrap: wrap;align-items: center;justify-content: center;flex-direction: column;margin: 0 auto;page-break-before:always;}\n" +
                "    .box{width: 96%;border: 1px solid #000;padding-bottom: 44%;height: 0;Position: relative;}\n" +
                "    .box:nth-child(n+1){margin-top: 1.4%;}\n" +
                "    .coupon{width: 100%;height: 100%;Position: absolute;display: flex;}\n" +
                "\n" +
                "    .left{flex: 1;}\n" +
                "    .right{flex: 1;}\n" +
                "\n" +
                "    .block{height: 70%;width: 96%;border-bottom-right-radius: 3rem;background: #57BCB8;overflow: hidden;Position: relative;top: -1px;left: -1px;}\n" +
                "    .blockrow{color: #ffffff;}\n" +
                "    .blockrow1{margin: 0.8rem;}\n" +
                "    .blockrow2{float: right;Position: absolute;right: 3rem;bottom: 1rem;}\n" +
                "    .pd{padding-left: 2rem;}\n" +
                "\n" +
                "    .blanck{height: 100%;width: 100%;padding: 0 2rem 0 1rem;overflow: hidden;Position: relative;}\n" +
                "    .logo{width: 3.4rem;height: 3.4rem;overflow: hidden;Position: absolute;right: 1rem;top: 0.4rem;}\n" +
                "    .barcode{width: 9.6rem;height: 5.25rem;margin-top: 1rem;}\n" +
                "    .img{width: 100%;height: 100%;}\n" +
                "\n" +
                "    .fs1{font-size: 4rem;line-height: 4rem;}\n" +
                "    .fs2{font-size: 6rem;line-height: 6rem;}\n" +
                "    .fs3{font-size: 2rem;line-height: 2rem;}\n" +
                "    .fs4{font-size: .8rem;line-height: 1.2rem;margin-top: 1rem;}\n" +
                "    .fs5{font-size: 1rem;line-height: 1rem;font-weight: bold;margin: 2rem 0;}\n" +
                "    .fs6{font-size: 1rem;line-height: 1.2rem;margin-top: 1rem;}\n" +
                "    \n" +
                "    @media print {\n" +
                "      .print_hide {display: none;}\n" +
                "      @page { size: auto; /* auto is the initial value */ margin: 0mm; /* this affects the margin in the printer settings */ }\n" +
                "    }\n" +
                "  </style>\n" +
                "  <title>优惠券打印单</title>\n" +
                "</head>\n" +
                "<body>\n"
        );

        List<List<DiscountTicket>> partition = Lists.partition(discountTicketList, 3);

        for (List<DiscountTicket> partList : partition) {
            sb.append("  <div class=\"paper\">");
            for (DiscountTicket ticket : partList) {
                if (ticket.getEndTime() == null) {
                    sb.append("<div class=\"box\"></div>");
                    continue;
                }

                String ticketType = null;

                ticketType = getDownloadTicketType(zh, ticket);

                List<String> shopNames = ticket.getShopList().stream().map(p -> p.getName()).collect(Collectors.toList());
                String companyName = getDownloadCompanyName(company, zh, ticket);

                String satisfy = getDownloadSatisfy(zh, ticket);

                String validDay = getDownloadValidDay(zh, ticket);

                String barCode = String.format("https://%s/%s", config.getProductBucketEndpoint(), ticket.getBarCodeImg());
                String companyLogo = String.format("https://%s/%s", config.getProductBucketEndpoint(), company.getCompanyLogo());

                //金额卷以及打折卷
                String nameString = null;
                if (zh) {
                    if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_CASH) {
                        nameString = String.format("     <span class=\"fs1\">$</span>\n" +
                                "                        <span class=\"fs2\">%s</span>\n", showMoneyDouble(ticket.getDiscountCash()));
                    } else {
                        nameString = String.format(
                                "     <span class=\"fs2\">%s</span>\n" +
                                        "                        <span class=\"fs1\">折</span>\n", showMoneyDouble(ticket.getDiscount()));
                    }
                } else {
                    if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_CASH) {
                        nameString = String.format("     <span class=\"fs1\">$</span>\n" +
                                "                        <span class=\"fs2\">%s</span>\n", showMoneyDouble(ticket.getDiscountCash()));
                    } else {
                        nameString = String.format(
                                "     <span class=\"fs2\">%s</span>\n" +
                                        "                        <span class=\"fs1\">%%</span>\n", ((10 - showMoneyDouble(ticket.getDiscount())) * 10));
                    }
                }

                String oneTicket = String.format(" <div class=\"box\">\n" +
                        "        <div class=\"coupon\">\n" +
                        "            <div class=\"left\">\n" +
                        "                <div class=\"block\">\n" +
                        "                    <div class=\"blockrow blockrow1\">\n" +
                        "                       %s" +
                        "                    </div>\n" +
                        "                    <div class=\"blockrow blockrow2 fs3\">%s</div>\n" +
                        "                </div>\n" +
                        "\n" +
                        "                <div class=\"pd\">\n" +
                        "                    <div class=\"fs6\">%s</div>\n" +
                        "                    <div class=\"fs4\">%s</div>\n" +
                        "                </div>\n" +
                        "            </div>\n" +
                        "\n" +
                        "\n" +
                        "            <div class=\"right\">\n" +
                        "                <div class=\"blanck\">\n" +
                        "                    <div class=\"fs5\">%s</div>\n" +
                        "                    <div class=\"fs4\">%s</div>\n" +
                        "                    <div class=\"barcode\">\n" +
                        "                        <img class=\"img\" src=\"%s\" alt=\"\">\n" +
                        "                    </div>\n" +
                        "                    <div class=\"logo\">\n" +
                        "                        <img class=\"img\" src=\"%s\" alt=\"\">\n" +
                        "                    </div>\n" +
                        "                </div>\n" +
                        "            </div>\n" +
                        "\n" +
                        "        </div>\n" +
                        "    </div>", nameString, ticketType, companyName, satisfy, validDay, ticket.getContentDescription(), barCode, companyLogo);

                sb.append(oneTicket);
            }

            sb.append("</div>\n");
        }

        sb.append("</body>\n" +
                "</html>");
        String randomCode = MongoId.generateId();
        File ticketFile = MongoId.getInstance().generateTmpFileWithName(String.format("%s-ticket-%s.html", randomCode, index));
        FileUtil.writeToFile(ticketFile, sb.toString());

        return ticketFile;
    }

    private String getDownloadTicketType(boolean zh, DiscountTicket ticket) {
        String ticketType;
        if (zh) {
            if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_CASH) {
                ticketType = "優惠券";
            } else {
                ticketType = "折扣券";
            }
        } else {
            ticketType = "Coupon";
        }
        return ticketType;
    }

    private String getDownloadValidDay(boolean zh, DiscountTicket ticket) {
        String validDay;
        if (zh) {
            validDay = String.format("有效期至%s", DateUtil.format(ticket.getEndTime(), "yyyy年MM月dd日"));
        } else {
            validDay = String.format("Valid Until %s", DateUtil.format(ticket.getEndTime(), "MM/dd/yyyy"));
        }
        return validDay;
    }

    private String getDownloadSatisfy(boolean zh, DiscountTicket ticket) {
        String satisfy;
        if (zh) {
            if (getBoolean(ticket.getMultiUsed())) {
                satisfy = String.format("消費滿$%s使用，可多張同時使用", showDouble(ticket.getAtLeastCost()));
            } else {
                satisfy = String.format("消費滿$%s使用,不可多張同時使用", showDouble(ticket.getAtLeastCost()));
            }
        } else {
            if (getBoolean(ticket.getMultiUsed())) {
                satisfy = String.format("Valid when spend $%s or more; applicable with other coupons", showDouble(ticket.getAtLeastCost()));
            } else {
                satisfy = String.format("Valid when spend $%s or more; Not applicable with other coupons", showDouble(ticket.getAtLeastCost()));
            }
        }
        return satisfy;
    }

    private String getDownloadCompanyName(Company company, boolean zh, DiscountTicket ticket) {
        String companyName;
        if (zh) {
            if (isEmpty(ticket.getTitleMsg())) {
                companyName = company.getName();
            } else {
                companyName = String.format("%s,適用于%s", company.getName(), ticket.getTitleMsg());
            }
        } else {
            if (isEmpty(ticket.getTitleMsg())) {
                companyName = company.getName();
            } else {
                companyName = String.format("%s, branches:%s", company.getName(), ticket.getTitleMsg());
            }
        }
        return companyName;
    }

    /**
     * 产生竖向的优惠卷
     * <p>
     * 6张一组
     *
     * @param discountTicketList
     * @return
     */
    public File generateVerticalTicketFile(List<DiscountTicket> discountTicketList, Company company, int index, boolean zh) throws Exception {
        //先判断能否被6整除，如果不能，则依次添加
        int leftCount = discountTicketList.size() % 6;
        if (leftCount != 0) {
            for (int i = 0; i < 6 - leftCount; i++) {
                discountTicketList.add(new DiscountTicket());
            }
        }

        StringBuilder sb = new StringBuilder();
        sb.append("<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
                "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
                "    <style>\n" +
                "        *{margin: 0;padding: 0;box-sizing: border-box;font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Liberation Sans\", \"PingFang SC\", \"Microsoft YaHei\", \"Hiragino Sans GB\", \"Wenquanyi Micro Hei\", \"WenQuanYi Zen Hei\", \"ST Heiti\", SimHei, SimSun, \"WenQuanYi Zen Hei Sharp\", sans-serif;}\n" +
                "        html, body{width: 100%;height: 100%;font-size: 20px;}\n" +
                "        .paper{width: 42rem;height: 59.4rem;display: flex;flex-wrap: wrap;align-items: center;justify-content: center;margin: 0 auto;page-break-before:always;}\n" +
                "        .box{width: 46%;border: 1px solid #000;padding-bottom: 46%;height: 0;Position: relative;}\n" +
                "        .box:nth-child(2n+1){margin-right: 1.4%;}\n" +
                "        .coupon{width: 100%;height: 100%;Position: absolute;}\n" +
                "\n" +
                "        .block{height: 40%;width: 96%;border-bottom-right-radius: 3rem;background: #57BCB8;overflow: hidden;Position: relative;top: -1px;left: -1px;}\n" +
                "        .blockrow{color: #ffffff;}\n" +
                "        .blockrow1{margin: 0.8rem;}\n" +
                "        .blockrow2{float: right;Position: absolute;right: 2rem;bottom: 1rem;}\n" +
                "\n" +
                "        .blanck{height: 60%;width: 100%;padding: 0 1rem;overflow: hidden;Position: relative;}\n" +
                "        .logo{width: 3.4rem;height: 3.4rem;overflow: hidden;Position: absolute;right: 1rem;bottom: 0.3rem;}\n" +
                "        .barcode{width:6.4rem;height:3.5rem;}\n" +
                "        .img{width: 100%;height: 100%;}\n" +
                "\n" +
                "        .fs1{font-size: 3rem;line-height: 3rem;}\n" +
                "        .fs2{font-size: 4rem;line-height: 4rem;}\n" +
                "        .fs3{font-size: 2rem;line-height: 2rem;}\n" +
                "        .fs4{font-size: 0.6rem;line-height: 0.8rem;margin-top: 0.4rem;}\n" +
                "        .fs5{font-size: 0.9rem;line-height: 0.9rem;font-weight: bold;margin: 0.4rem 0;}\n" +
                "\n" +
                "        @media print {\n" +
                "            .print_hide {display: none;}\n" +
                "            @page { size: auto; /* auto is the initial value */ margin: 0mm; /* this affects the margin in the printer settings */ }\n" +
                "        }\n" +
                "    </style>\n" +
                "    <title>Coupons</title>\n" +
                "</head>\n" +
                "<body>\n");

        List<List<DiscountTicket>> partition = Lists.partition(discountTicketList, 6);

        for (List<DiscountTicket> partList : partition) {
            sb.append("<div class=\"paper\" id=\"printMe\">");

            //添加中间的值
            for (DiscountTicket ticket : partList) {
                if (ticket.getEndTime() == null) {
                    sb.append("<div class=\"box\"></div>");
                    continue;
                }

                String companyName = getDownloadCompanyName(company, zh, ticket);
                ;

                String nameString = null;
                if (zh) {
                    if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_CASH) {
                        nameString = String.format("                    <span class=\"fs1\">$</span>\n" +
                                "                    <span class=\"fs2\">%s</span>\n", showMoneyDouble(ticket.getDiscountCash())
                        );
                    } else {
                        nameString = String.format("                    <span class=\"fs2\">%s</span>\n" +
                                "                    <span class=\"fs1\">折</span>\n", showMoneyDouble(ticket.getDiscount())
                        );
                    }
                } else {
                    if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_CASH) {
                        nameString = String.format("                    <span class=\"fs1\">$</span>\n" +
                                "                    <span class=\"fs2\">%s</span>\n", showMoneyDouble(ticket.getDiscountCash())
                        );
                    } else {
                        nameString = String.format("                    <span class=\"fs2\">%s</span>\n" +
                                "                    <span class=\"fs1\">%%</span>\n", ((10 - showMoneyDouble(ticket.getDiscount())) * 10)
                        );
                    }
                }

                String satisfy = getDownloadSatisfy(zh, ticket);

                String validDay = getDownloadValidDay(zh, ticket);

                String barCode = String.format("https://%s/%s", config.getProductBucketEndpoint(), ticket.getBarCodeImg());
                String companyLogo = String.format("https://%s/%s", config.getProductBucketEndpoint(), company.getCompanyLogo());

                String ticketType = getDownloadTicketType(zh, ticket);

                String oneTicket = String.format("<div class=\"box\">\n" +
                        "        <div class=\"coupon\">\n" +
                        "            <div class=\"block\">\n" +
                        "                <div class=\"blockrow blockrow1\">\n" +
                        "                  %s" +
                        "                </div>\n" +
                        "                <div class=\"blockrow blockrow2 fs3\">%s</div>\n" +
                        "            </div>\n" +
                        "            <div class=\"blanck\">\n" +
                        "                <div class=\"fs4\">%s</div>\n" +
                        "                <div class=\"fs4\">%s</div>\n" +
                        "                <div class=\"fs4\">%s</div>\n" +
                        "                <div class=\"fs4\">%s</div>\n" +
                        "                <div class=\"barcode\">\n" +
                        "                    <img class=\"img\" src=\"%s\" alt=\"\">\n" +
                        "                </div>\n" +
                        "                <div class=\"logo\">\n" +
                        "                    <img class=\"img\" src=\"%s\" alt=\"\">\n" +
                        "                </div>\n" +
                        "            </div>\n" +
                        "        </div>\n" +
                        "    </div>", nameString, ticketType, companyName, satisfy, ticket.getContentDescription(), validDay, barCode, companyLogo);

                sb.append(oneTicket);
            }

            sb.append("</div>\n");
        }

        sb.append("</body>\n" +
                "</html>");
        String randomCode = MongoId.generateId();
        File ticketFile = MongoId.getInstance().generateTmpFileWithName(String.format("%s-ticket-%s.html", randomCode, index));
        FileUtil.writeToFile(ticketFile, sb.toString());

        return ticketFile;
    }

    /**
     * 生成第一种格式
     *
     * @param ticket
     * @param company
     * @return
     */
    public File generateTicketImageForFirstStyle(DiscountTicket ticket, Company company) throws Exception {
        String fileContent;

        String ticketType = "優惠券";
        List<String> shopNames = ticket.getShopList().stream().map(p -> p.getName()).collect(Collectors.toList());
        String companyName = String.format("%s,適用于%s", company.getName(), ticket.getTitleMsg());
        String satisfy = null;

        if (getBoolean(ticket.getMultiUsed())) {
            satisfy = String.format("消費滿$%s使用，可多張同時使用", showDouble(ticket.getAtLeastCost()));
        } else {
            satisfy = String.format("消費滿$%s使用,不可多張同時使用", showDouble(ticket.getAtLeastCost()));
        }

        String validDay = null;
        validDay = String.format("有效期至%s", DateUtil.format(ticket.getEndTime(), "yyyy年MM月dd日"));

        String barCode = String.format("https://%s/%s", config.getProductBucketEndpoint(), ticket.getBarCodeImg());
        String companyLogo = String.format("https://%s/%s", config.getProductBucketEndpoint(), company.getCompanyLogo());

        if (getInt(ticket.getTicketType()) == DISCOUNT_TICKET_TYPE_CASH) {
            fileContent = String.format("<!DOCTYPE html>\n" +
                    "<html lang=\"en\">\n" +
                    "<head>\n" +
                    "    <meta charset=\"UTF-8\">\n" +
                    "    <title>ticket</title>\n" +
                    "</head>\n" +
                    "<body>\n" +
                    "<div style=\"width: 600px\">\n" +
                    "    <div style=\"font-weight:bold;height: 300px;background-color: rgb(87, 188, 184);border-bottom-right-radius:25px;\">\n" +
                    "        <div style=\"padding-left: 5%%\">\n" +
                    "            <div style=\"font-size: 100px;color: white; display:inline\">$</div>\n" +
                    "            <div style=\"font-size: 150px;color: white; display:inline\">%s</div>\n" +
                    "\n" +
                    "        </div>\n" +
                    "        <div>\n" +
                    "            <div style=\"float:right;margin-right:5%%;color: white;font-size: 50px\">\n" +
                    "                %s\n" +
                    "            </div>\n" +
                    "        </div>\n" +
                    "    </div>\n" +
                    "\n" +
                    "    <div style=\"padding-top:5%%;font-size: 20px; padding-right: 5%%\">\n" +
                    "        <div style=\"padding-left: 5%%\">\n" +
                    "            <!--   公司信息 -->\n" +
                    "            <div style=\"padding-bottom: 2%%\">%s</div>\n" +
                    "            <!--    门槛，以及是否可以同时使用-->\n" +
                    "            <div style=\"padding-bottom: 2%%\">%s</div>\n" +
                    "            <!--    描述 -->\n" +
                    "            <div style=\"padding-bottom: 5%%\">%s</div>\n" +
                    "            <!-- 有效期 -->\n" +
                    "            <div>%s</div>\n" +
                    "<!--            条形码-->\n" +
                    "            <!--            <img src=\"https://cd-jinchen-public.oss-cn-zhangjiakou.aliyuncs.com/discount-0601895181.png\">-->\n" +
                    "            <img src=\"%s\">\n" +
                    "\n" +
                    "<!--            LOGO-->\n" +
                    "            <div style=\"display:inline\">\n" +
                    "                <!--                <img style=\"float: right\" src=\"https://cd-jinchen-public.oss-cn-zhangjiakou.aliyuncs.com/602a80a6a792c80ac2ebeb9d.jpg\">-->\n" +
                    "                <img style=\"float: right\" src=\"%s\">\n" +
                    "            </div>\n" +
                    "        </div>\n" +
                    "\n" +
                    "        <div>\n" +
                    "\n" +
                    "        </div>\n" +
                    "\n" +
                    "    </div>\n" +
                    "\n" +
                    "    <div>\n" +
                    "\n" +
                    "    </div>\n" +
                    "\n" +
                    "</div>\n" +
                    "\n" +
                    "</body>\n" +
                    "</html>\n", showMoneyDouble(ticket.getDiscountCash()), ticketType, companyName, satisfy, ticket.getContentDescription(), validDay, barCode, companyLogo);
        } else {
            fileContent = String.format("<!DOCTYPE html>\n" +
                    "<html lang=\"en\">\n" +
                    "<head>\n" +
                    "    <meta charset=\"UTF-8\">\n" +
                    "    <title>ticket</title>\n" +
                    "</head>\n" +
                    "<body>\n" +
                    "<div style=\"width: 600px\">\n" +
                    "    <div style=\"font-weight:bold;height: 300px;background-color: rgb(87, 188, 184);border-bottom-right-radius:25px;\">\n" +
                    "        <div style=\"padding-left: 5%%\">\n" +
                    "            <div style=\"font-size: 150px;color: white; display:inline\">%s</div>\n" +
                    "            <div style=\"font-size: 100px;color: white; display:inline\">折</div>\n" +
                    "\n" +
                    "        </div>\n" +
                    "        <div>\n" +
                    "            <div style=\"float:right;margin-right:5%%;color: white;font-size: 50px\">\n" +
                    "                %s\n" +
                    "            </div>\n" +
                    "        </div>\n" +
                    "    </div>\n" +
                    "\n" +
                    "    <div style=\"padding-top:5%%;font-size: 20px; padding-right: 5%%\">\n" +
                    "        <div style=\"padding-left: 5%%\">\n" +
                    "            <div style=\"padding-bottom: 2%%\">%s</div>\n" +
                    "            <div style=\"padding-bottom: 2%%\">%s</div>\n" +
                    "            <div style=\"padding-bottom: 5%%\">%s</div>\n" +
                    "            <div>%s</div>\n" +
                    "<!--            <img src=\"https://cd-jinchen-public.oss-cn-zhangjiakou.aliyuncs.com/discount-0601895181.png\">-->\n" +
                    "                        <img src=\"%s\">\n" +
                    "\n" +
                    "            <div style=\"display:inline\">\n" +
                    "<!--                <img style=\"float: right\" src=\"https://cd-jinchen-public.oss-cn-zhangjiakou.aliyuncs.com/602a80a6a792c80ac2ebeb9d.jpg\">-->\n" +
                    "                <img style=\"float: right\" src=\"%s\">\n" +
                    "            </div>\n" +
                    "        </div>\n" +
                    "\n" +
                    "        <div>\n" +
                    "\n" +
                    "        </div>\n" +
                    "\n" +
                    "    </div>\n" +
                    "\n" +
                    "    <div>\n" +
                    "\n" +
                    "    </div>\n" +
                    "\n" +
                    "</div>\n" +
                    "\n" +
                    "</body>\n" +
                    "</html>\n", (int) (ticket.getDiscount() * 10), ticketType, companyName, satisfy, ticket.getContentDescription(), validDay, barCode, companyLogo);
        }

        File ticketFile = MongoId.getInstance().generateTmpFileWithName(String.format("ticket-%s.html", ticket.getCode()));
        FileUtil.writeToFile(ticketFile, fileContent);

        logger.info("the content is {}", fileContent);
        logger.info("file is {}", ticketFile.getAbsolutePath());

        return ticketFile;
    }

    /**
     * 通过CODE查询优惠卷
     *
     * @param code
     * @return
     */
    public Optional<DiscountTicket> findTicket(String code, Long companyId) {
        DiscountTicket ticket = new DiscountTicket();
        ticket.setCode(code);
        ticket.setCompanyId(companyId);
        ticket.setEntity(true);
        Optional<DiscountTicket> discountTicketOptional = commonService.searchOneOptional(ticket);

        if (discountTicketOptional.isPresent()) {
            try {
                syncParentTicket(discountTicketOptional.get());
            } catch (Exception e) {
                logger.error("e", e);
            }
        }

        return discountTicketOptional;
    }

    /**
     * 将订单里面的优惠卷绑定到当前会话
     *
     * @param reqOrder
     */
    public void bindTicketToSession(Order reqOrder) throws Exception {
        Long companyId = OrderService.getInstance().findCompanyId(reqOrder);
        List<String> ticketCodeList = reqOrder.getTicketCodeList();
        if (isEmpty(ticketCodeList)) {
            return;
        }

        String sessionId = ServletUtil.getSessionId();

        for (String code : ticketCodeList) {
            Optional<DiscountTicket> ticketOptional = findTicket(code, companyId);
            if (ticketOptional.isPresent()) {
                DiscountTicket ticket = ticketOptional.get();
                ticket.setBindingSessionId(sessionId);
                commonService.save(ticket);
            }
        }
    }

    /**
     * 获取所有的优惠卷码
     *
     * @param orderInDb
     * @return
     */
    public List<String> getAllTicket(Order orderInDb) {
        List<String> ticketCodeList = new ArrayList<>();

        if (isNotEmpty(orderInDb.getParentTicketCodeList())) {
            ticketCodeList.addAll(orderInDb.getParentTicketCodeList());
        }

        if (isNotEmpty(orderInDb.getTicketCodeList())) {
            ticketCodeList.addAll(orderInDb.getTicketCodeList());
        }

        return new ArrayList<String>(new HashSet<String>(ticketCodeList));
    }

    /**
     * 是否是线上的优惠卷
     *
     * @param ticketId
     * @return
     */
    public boolean isOnlineTicket(Long ticketId) {
        try {
            Optional<DiscountTicket> discountTicketOptional = commonService.searchOneOptional(ticketId, DiscountTicket.class);
            if (!discountTicketOptional.isPresent()) {
                return false;
            }

            return getBoolean(discountTicketOptional.get().getOnlineTicket());
        } catch (Exception e) {
            logger.error("e", e);
            return false;
        }

    }

    /**
     * 获取中文
     *
     * @param discountTicket
     * @return
     */
    public String getTicketNameZh(DiscountTicket discountTicket) {
        if (isNotEmpty(discountTicket.getName_zh())) {
            return discountTicket.getName_zh();
        }

        if (isNotEmpty(discountTicket.getName())) {
            return discountTicket.getName();
        }

        return discountTicket.getName_en();
    }

    /**
     * 获取英文名
     *
     * @param discountTicket
     * @return
     */
    public String getTicketNameEn(DiscountTicket discountTicket) {
        if (isNotEmpty(discountTicket.getName_en())) {
            return discountTicket.getName_en();
        }

        if (isNotEmpty(discountTicket.getName())) {
            return discountTicket.getName();
        }

        return discountTicket.getName_zh();


    }

    public DiscountTicket createRealTicketForAssignByExcel(DiscountTicket parentTicket, CustomerTicket customerTicket) throws Exception {
        //创建优惠券
        DiscountTicket realTicket = new DiscountTicket();
        BeanUtils.copyProperties(parentTicket, realTicket, "id", "template", "createTime", "createDate");
        realTicket.setCreateTime(null);
        realTicket.setParentId(parentTicket.getId());
        realTicket.setTemplate(false);
        realTicket.setUsed(false);
        String code = generateCode(parentTicket.getCompanyId());
        realTicket.setBarCodeImg(String.format("discount-%s.png", code));
        realTicket.setCode(code);
        realTicket.setAssignByExcel(true);
        realTicket.setExpiredTime(customerTicket.getExpiredTime());
        realTicket.setEndTime(customerTicket.getExpiredTime());
        realTicket.setStartTime(System.currentTimeMillis());
        commonService.createObject(realTicket, null, false, null);
        return realTicket;
    }

    /**
     * 创建真实可用的优惠券
     *
     * @param discountTicket
     * @return
     * @throws Exception
     */
    public DiscountTicket createRealTicket(DiscountTicket discountTicket) throws Exception {
        DiscountTicket realTicket = new DiscountTicket();
        BeanUtils.copyProperties(discountTicket, realTicket, "id", "template", "createTime", "createDate");
        realTicket.setCreateTime(null);
        realTicket.setParentId(discountTicket.getId());
        realTicket.setTemplate(false);
        realTicket.setUsed(false);
        String code = generateCode(discountTicket.getCompanyId());
        realTicket.setBarCodeImg(String.format("discount-%s.png", code));

        realTicket.setCode(code);

        if (getLong(discountTicket.getExpiredTime()) > 0) {
            realTicket.setStartTime(discountTicket.getStartTime());
            Long expiredTime = discountTicket.getExpiredTime();
            realTicket.setEndTime(DateUtil.endTimeInDay(expiredTime));
            realTicket.setExpiredTime(DateUtil.endTimeInDay(expiredTime));
        } else if (discountTicket.getBindingDays() != null && getInt(discountTicket.getBindingDays()) >= 0) {
            long currentTimeMillis = System.currentTimeMillis();
            long expireTime = DateUtil.endTimeInDay(currentTimeMillis + getInt(realTicket.getBindingDays()) * DateUtil.ONE_DAY);
            realTicket.setStartTime(currentTimeMillis);
            realTicket.setEndTime(DateUtil.endTimeInDay(expireTime));
            realTicket.setExpiredTime(DateUtil.endTimeInDay(expireTime));
        }

        //创建真实可用的优惠卷，但是不校验名称
        commonService.createObject(realTicket, null, false, null);

        return realTicket;
    }

    /**
     * 将结束时间格式化
     *
     * @param discountTicket
     * @return
     */
    public long formatEndTime(DiscountTicket discountTicket) throws ParseException {
        if (discountTicket.getEndTime() == null) {
            return 0;
        }

        Long endTime = discountTicket.getEndTime();
//        String endDay = DateUtil.format(endTime, "yyyy-MM-dd");
//        Date date = DateUtil.stringToDate("yyyy-MM-dd", endDay);
//        endTime = date.getTime() + DateUtil.ONE_DAY - DateUtil.ONE_SECONDS;
        return endTime;
    }

    /**
     * 给菜品券添加主菜的名称
     *
     * @param discountTicket
     */
    public void addCompanyMainItemList(DiscountTicket discountTicket) {
        if (getBoolean(discountTicket.getItemTicket())) {
            List<CompanyMainItem> companyMainItemList = getList(discountTicket.getMainItemIdList()).stream().map(mainItemId -> {
                try {
                    return commonService.findEntity(mainItemId, CompanyMainItem.class);
                } catch (Exception e) {
                    return null;
                }
            }).filter(p -> p != null).collect(Collectors.toList());
            discountTicket.setCompanyMainItemList(companyMainItemList);
        }
    }

    /**
     * 将优惠券设置成已过期
     *
     * @param code
     * @param companyId
     */
    public void setTicketToExpired(String code, Long companyId) {
        Optional<DiscountTicket> discountTicketOptional = findTicket(code, companyId);
        if (!discountTicketOptional.isPresent()) {
            return;
        }

        DiscountTicket discountTicket = discountTicketOptional.get();
        discountTicket.setExpired(true);
        try {
            commonService.save(discountTicket);
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 是否是店长优惠券
     *
     * @param discountTicket
     * @return
     */
    public boolean isWaiterLeaderTicket(DiscountTicket discountTicket) {
        if (discountTicket == null) {
            logger.info("discount ticket is null");
            return false;
        }

        return discountTicket.getCustomerId() != null && discountTicket.getCustomerId() == WAITER_LEADER_TICKET;
    }

    /**
     * 删除优惠卷时，其他地方是否在使用
     *
     * @param discountTicket
     * @throws ResponseStatusException
     */
    public void verifyTicketInUse(DiscountTicket discountTicket) throws ResponseStatusException {
        CustomerService customerService = CustomerService.getInstance();
        //再根据公司找到营销任务
        List<MarketTask> marketTaskListInDb = customerService.findMarketTaskByCompanyId(discountTicket.getCompanyId());
        //收集到使用了该优惠券的营销任务
        List<MarketTask> marketTaskList = new ArrayList<>();
        for (MarketTask marketTask : marketTaskListInDb) {
            //找到营销任务在使用该优惠券
            List<TicketAndLimit> findMarketTask = marketTask.getTicketAndLimitList().stream().filter(s -> equals(s.getTicketId(), discountTicket.getId())).collect(Collectors.toList());
            if (isNotEmpty(findMarketTask)) {
                marketTaskList.add(marketTask);
            }
        }

        List<String> marketTaskNameZhList = null;
        List<String> marketTaskNameEnList = null;
        if (isNotEmpty(marketTaskList)) {
            //收集使用该优惠券的营销任务名字
            marketTaskNameZhList = marketTaskList.stream().map(s -> s.getTaskName_zh()).collect(Collectors.toList());
            marketTaskNameEnList = marketTaskList.stream().map(s -> s.getTaskName_en()).collect(Collectors.toList());
        }
        //根据公司找到会员等级
        VipLevel vipLevel = new VipLevel();
        vipLevel.setCompanyId(discountTicket.getCompanyId());
        List<VipLevel> vipLevelListInDb = commonService.searchAll(vipLevel);
        List<VipLevel> vipLevelList = new ArrayList<>();
        //再看每个等级都有哪些优惠券，是否使用了该优惠卷
        for (VipLevel viplevel : vipLevelListInDb) {
            VipLevelTicketConfig vipLevelTicketConfig = new VipLevelTicketConfig();
            vipLevelTicketConfig.setLevelId(viplevel.getId());
            //每个等级所拥有的优惠券
            List<VipLevelTicketConfig> vipLevelTicketConfigListInDb = commonService.searchAll(vipLevelTicketConfig);
            List<VipLevelTicketConfig> vipLevelTicketConfigList = vipLevelTicketConfigListInDb.stream().filter(s -> equals(s.getTicketId(), discountTicket.getId())).collect(Collectors.toList());
            if (isNotEmpty(vipLevelTicketConfigList)) {
                vipLevelList.add(viplevel);
            }

        }
        List<String> vipLevelNameZh = null;
        List<String> vipLevelNameEn = null;
        if (isNotEmpty(vipLevelList)) {
            //收集使用该优惠券的会员等级
            vipLevelNameZh = vipLevelList.stream().map(s -> s.getName_zh()).collect(Collectors.toList());
            vipLevelNameEn = vipLevelList.stream().map(s -> s.getName_en()).collect(Collectors.toList());
        }
        //会员等级和营销任务都使用了该优惠券
        if (isNotEmpty(vipLevelList) && isNotEmpty(marketTaskList)) {
            List[] listZh = {vipLevelNameZh, marketTaskNameZhList};
            List[] listEn = {vipLevelNameEn, marketTaskNameEnList};
            VerifyUtil.verifyZhEn(() -> false, DELETE_TICKET_HINT, listZh, listEn);
        }
        //会员等级使用了该优惠卷
        if (isNotEmpty(vipLevelList)) {
            VerifyUtil.verifyZhEn(() -> false, DELETE_TICKET_IN_VIP, new List[]{vipLevelNameZh}, new List[]{vipLevelNameEn});
        }
        //营销任务使用了该优惠卷
        if (isNotEmpty(marketTaskList)) {
            VerifyUtil.verifyZhEn(() -> false, DELETE_TICKET_IN_MARKET_TASK, new List[]{marketTaskNameZhList}, new List[]{marketTaskNameEnList});
        }

    }
}